#include "WebManagerPair.h"
#include "ServerManager.h"

#include "comm_def.h"

#include <functional>

void WebManagerPair::SClientRespAsyncCallBack(uS::Async* handle)
{
	assert(handle);
	WebManagerPair* pWebManagerPair = static_cast<WebManagerPair*>(handle->getData());
	pWebManagerPair->SendClientResponse();
}

void WebManagerPair::NotifyClientResponse()
{
	if (_clientRespAsync)
	{
		_clientRespAsync->send();
	}
}

void WebManagerPair::PushWebSocketClientResponse(ResponseType type, SessionType sid, const char* msg, size_t len)
{
	if (sid == INVALID_SESSION_ID || !msg)
	{ //record some error message
		return;
	}
	_msgQueueP->AddWebResponseMessage(sid, msg, len, type);
}

WebManagerPair::WebManagerPair()
{
}


bool WebManagerPair::InitWebManagerPair(std::string ip, uint16_t port, std::shared_ptr<MessageQueueManager> msgqueue)
{
	bool bret = false;
	_listenIP = ip;
	_listenPort = port;
	_msgQueueP = msgqueue;
	_logger = spdlog::get(LOGGER_NAME);
	_recvThread = std::make_shared<std::thread>(&WebManagerPair::RecvDataThreadFunc, this);
	if (_logger)
	{
		bret = true;
	}
	return bret;
}

void WebManagerPair::StartWebManagerPair()
{
	_recvThread->join();
}

WebManagerPair::~WebManagerPair()
{
}

void WebManagerPair::RecvDataThreadFunc()
{
	uWS::Hub h;
	_clientRespAsync = std::make_shared<uS::Async>(h.getLoop());
	_clientRespAsync->setData(this);
	_clientRespAsync->start(&WebManagerPair::SClientRespAsyncCallBack);
	uWS::Group<uWS::SERVER>* ccc = h.createGroup<uWS::SERVER>();
	ccc->onMessage([](uWS::WebSocket<uWS::SERVER> *ws, char *message, size_t length, uWS::OpCode opCode)
		{
			ws->send(message, length, opCode);
		});
	//uWS::Group<uWS::SERVER> newGroupx = h.createGroup<uWS::Group<uWS::SERVER>>();
	h.onConnection([&h,ccc, this](uWS::WebSocket<uWS::SERVER> *ws, uWS::HttpRequest request)
		{ //new connection
			AddSession(ws);
		});

	h.onMessage([this](uWS::WebSocket<uWS::SERVER> *ws, char *message, size_t length, uWS::OpCode opCode) 
		{
			auto sessionid = GetSessionIDByWebSocket(ws);
			_msgQueueP->AddWebRequestMessage(sessionid, message, length);
		});
	h.onDisconnection([this](uWS::WebSocket<uWS::SERVER>* ws, int code, char* message, size_t lenght) 
		{
			RemoveSession(ws);
		});
	if (!h.listen(_listenIP.c_str(),_listenPort, nullptr, uS::ListenOptions::REUSE_PORT)) 
	{

	}
	h.run();
}

void WebManagerPair::SendClientResponse()
{
	auto msgResp = _msgQueueP->GetWebMessageResp();
	while (msgResp->sessionid != INVALID_SESSION_ID)
	{
		switch (msgResp->respType)
		{
		case ResponseType::broadcast: //广播
		{

		}break;
		case ResponseType::multicast: //多播
		{

		}break;
		case ResponseType::unicast: //单播
		{
			auto respSession = GetWebSocketByUnicastSessionID(msgResp->sessionid);
			if (respSession)
			{
				respSession->send(msgResp->msg.c_str());
			}
		}break;
		default:
			break;
		}
		msgResp = _msgQueueP->GetWebMessageResp();
	}
}


SessionType WebManagerPair::AddSession(uWS::WebSocket<uWS::SERVER>* ws)
{
	if (!ws || _websocketSessions.right.find(ws) != _websocketSessions.right.end())
	{
		return INVALID_SESSION_ID;
	}
	auto newsRet = ServerManager::SGetSessionIndex();
	_websocketSessions.insert({ newsRet, ws });
	return newsRet;
}

SessionType WebManagerPair::RemoveSession(uWS::WebSocket<uWS::SERVER>* ws)
{
	if (!ws || _websocketSessions.right.find(ws) == _websocketSessions.right.end())
	{
		return INVALID_SESSION_ID;
	}
	auto it = _websocketSessions.right.find(ws);
	auto sRet = it->second;
	_websocketSessions.right.erase(it);
	return sRet;
}

SessionType WebManagerPair::GetSessionIDByWebSocket(uWS::WebSocket<uWS::SERVER>* ws)
{
	SessionType sRet{ INVALID_SESSION_ID };
	auto it = _websocketSessions.right.find(ws);
	sRet = (it == _websocketSessions.right.end()) ? INVALID_SESSION_ID : it->second;
	return sRet;
}

uWS::WebSocket<uWS::SERVER>* WebManagerPair::GetWebSocketByUnicastSessionID(SessionType sessiond)
{
	uWS::WebSocket<uWS::SERVER>* pRet = nullptr;
	auto it = _websocketSessions.left.find(sessiond);
	if (it != _websocketSessions.left.end())
	{
		pRet = it->second;
	}
	return pRet;
}

